#include "SudokuFish.h"

SudokuFish::SudokuFish(QString name, CellFillerTypes type, int fishSize, QObject* parent) :
        SudokuAbstractSolvingTechnique(name, type, EliminateCandidate, parent),
        mFishSize(fishSize)
{
    Q_ASSERT(mFishSize > 1);
    Q_ASSERT(mFishSize <= 10);
}

int SudokuFish::solve()
{
    for(int candidate=0; candidate<mSudokuData->getSize(); ++candidate)
    {
        // Map indexed by bit array of possible candidates, value list of houses with that possible array
        QHash<QBitArray, QList<int> > mapOfRowHouses;
        QHash<QBitArray, QList<int> > mapOfColHouses;

        for(int houseInd=0; houseInd<mSudokuData->getSize(); ++houseInd)
        {
            QBitArray candidateRowArray = mSudokuData->houseAtRow(houseInd)->getCellsArrayWithCandidate(candidate);
            QBitArray candidateColArray = mSudokuData->houseAtCol(houseInd)->getCellsArrayWithCandidate(candidate);

            if(candidateRowArray.count(true) == mFishSize)
            {
                mapOfRowHouses[candidateRowArray].append(houseInd);
            }

            if(candidateColArray.count(true) == mFishSize)
            {
                mapOfColHouses[candidateColArray].append(houseInd);
            }
        }

        //qDebug() << "SudokuFish::solve mapOfRowHouses size=" << mapOfRowHouses.size();

        QHashIterator<QBitArray, QList<int> > iterRow(mapOfRowHouses);
        while(iterRow.hasNext())
        {
            iterRow.next();

            // TODO improve elimination
            if(iterRow.value().count() == mFishSize)
            {
                qDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!SudokuFish::solve FOUND ROW " << iterRow.value() << " with array " << iterRow.key().size() << " for candidate " << QString::number(candidate + 1);
                QList<int> rowIndexList = iterRow.value();

                QBitArray candidateArr = iterRow.key();

                QList<int> candidateL;
                candidateL.append(candidate);

                for(int colIndex = 0; colIndex<candidateArr.size(); ++colIndex)
                {
                    if(candidateArr.testBit(colIndex))
                    {
                        SudokuCellSet omitCells;
                        for(int rowIndex = 0; rowIndex<rowIndexList.size(); ++ rowIndex)
                        {
                            omitCells.append(mSudokuData->houseAtCol(colIndex)->at(rowIndexList.at(rowIndex)));
                        }
                        SudokuHouse* house = mSudokuData->houseAtCol(colIndex);
                        mCount += house->eliminate(candidateL, mType, omitCells);
                    }
                }

            }
        }



        QHashIterator<QBitArray, QList<int> > iterCol(mapOfColHouses);
        while(iterCol.hasNext())
        {
            iterCol.next();

            // TODO improve elimination
            if(iterCol.value().count() == mFishSize)
            {
                qDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!SudokuFish::solve FOUND COL " << iterCol.value() << " with array " << iterCol.key().size() << " for candidate " << QString::number(candidate + 1);
                QList<int> colIndexList = iterCol.value();

                QBitArray candidateArr = iterCol.key();

                QList<int> candidateL;
                candidateL.append(candidate);

                for(int rowIndex = 0; rowIndex<candidateArr.size(); ++rowIndex)
                {
                    if(candidateArr.testBit(rowIndex))
                    {
                        SudokuCellSet omitCells;
                        for(int colIndex = 0; colIndex<colIndexList.size(); ++ colIndex)
                        {
                            omitCells.append(mSudokuData->houseAtRow(rowIndex)->at(colIndexList.at(colIndex)));
                        }
                        SudokuHouse* house = mSudokuData->houseAtRow(rowIndex);
                        mCount += house->eliminate(candidateL, mType, omitCells);
                    }
                }

            }
        }


    }

    qDebug() << "SudokuFish::solve mCount: " << mCount;
    return mCount;
}
